/*
 *  processmgtbase.cpp
 *
 *  Created on: 2011-4-9
 *      Author: chenl
 */

#include "processmgtbase.h"
#include "os/sched.h"
#include "common/common_err.h"
#include "task_wrapper.h"
#include "global.h"

#define TASK_HASH_LIST_END		taskHashList_.end()
#define RUNQUEUE_END			pRunQueue_->end()
#define WAITQUEUE_END			pWaitQueue_->end()

#define TASK_HASH_LIST_NULL		TASK_HASH_LIST_END
#define RUNQUEUE_NULL			RUNQUEUE_END
#define WAITQUEUE_NULL			WAITQUEUE_END

#define DEFAULT_PROCESSMGT_LOGPREFIX	"./log/psmgt"

CProcessMgtBase::CProcessMgtBase() :
	logEngine(DEFAULT_PROCESSMGT_LOGPREFIX, LOGLEVEL), init_(0),  pRoot_(0), current_(0),
	pRunQueue_(&taskQueue_[0]), pWaitQueue_(&taskQueue_[1])
{

}

CProcessMgtBase::~CProcessMgtBase()
{
	// TODO Auto-generated destructor stub
}

int32_t CProcessMgtBase::Initialize()
{
	init_ = &CTask::InitTask();
	pRoot_ = init_;
	current_ = init_;
	return S_OK;
}

int32_t CProcessMgtBase::Uninitialize()
{
	return S_OK;
}

int32_t CProcessMgtBase::NewTask(CTask& oldTask, CTask& newTask)
{
	struct task_struct *p = &oldTask.task;
	struct task_struct *q = &newTask.task;

	logEngine.WriteLog(enmLogLevel_DEBUG,
				"fork... father=%d, child=%d", p->pid, q->pid);

	if(NULL != p->p_cptr)
	{
		p->p_cptr->p_ysptr = q;
	}
	q->p_osptr = p->p_cptr;
	q->p_pptr = q->p_opptr = p;
	p->p_cptr = q;

	InsertTaskToHashList(newTask);

	return S_OK;
}

int32_t CProcessMgtBase::DeleteTask(CTask& task)
{
	int32_t ret = S_OK;
	struct task_struct* p = &task.task;
	if (IsTaskOnRunQueue(task))
	{
		logEngine.WriteLog(enmLogLevel_DEBUG,
				"Deleting Task(pid=%d), task is in runqueue!", p->pid);
		ret = DelTaskFromRunqueue(task);
		if (0 > ret)
		{
			logEngine.WriteLog(enmLogLevel_WARN,
					"Delete task(pid=%d) in runqueue failed", p->pid);
			ret = E_PS_DELETETASKFAIL;
		}
	}
	if (IsTaskOnWaitQueue(task))
	{
		logEngine.WriteLog(enmLogLevel_DEBUG,
				"Deleting Task(pid=%d), task is in waitqueue!", p->pid);
		ret = DelTaskFromWaitQueue(task);
		if (0 > ret)
		{
			logEngine.WriteLog(enmLogLevel_WARN,
					"Delete task(pid=%d) in waitqueue failed", p->pid);
			ret = E_PS_DELETETASKFAIL;
		}
	}
	if (IsTaskOnHashList(p->pid))
	{
		logEngine.WriteLog(enmLogLevel_DEBUG,
				"Deleting Task(pid=%d), task is in hashlist!", p->pid);
		ret = DelTaskFromHashList(p->pid);
		if (0 > ret)
		{
			logEngine.WriteLog(enmLogLevel_WARN,
					"Delete task(pid=%d) in hashlist failed", p->pid);
			ret = E_PS_DELETETASKFAIL;
		}
	}
	ret = DelTaskFromProcessTree(task);
	if (0 > ret)
	{
		logEngine.WriteLog(enmLogLevel_WARN,
				"Delete task(pid=%d) in process tree failed", p->pid);
	}
	return ret;
}

int32_t CProcessMgtBase::DeleteTask(pid_t pid)
{
	TaskHashListItr itr = FindTaskFromHashList(pid);
	if (TASK_HASH_LIST_END == itr)
	{
		logEngine.WriteLog(enmLogLevel_DEBUG,
				"Deleting Task(pid=%d), task is in hashlist!", pid);
		return E_PS_PIDNOTFOUND;
	}
	CTask* pTask = itr->second;
	if (unlikely(NULL == pTask))
	{
		logEngine.WriteLog(enmLogLevel_FATAL, "Found pid=%d but address is NULL", pid);
		return E_PS_HASHLIST_CLOBBERED;
	}
	return DeleteTask(*pTask);
}

int32_t CProcessMgtBase::InsertToRunQueue(CTask& task)
{
	struct task_struct* p = &task.task;
	logEngine.WriteLog(enmLogLevel_DEBUG,
			"Inserting task(pid=%d) into runqueue", p->pid);
	InsertTaskToQueue(task, *pRunQueue_);
	return S_OK;
}

int32_t CProcessMgtBase::InsertToWaitQueue(CTask& task)
{
	struct task_struct* p = &task.task;
	logEngine.WriteLog(enmLogLevel_DEBUG,
			"Inserting task(pid=%d) into waitqueue", p->pid);
	InsertTaskToQueue(task, *pWaitQueue_);
	return S_OK;
}

int32_t CProcessMgtBase::InsertTaskToHashList(CTask& task)
{
	struct task_struct* p = &task.task;
	logEngine.WriteLog(enmLogLevel_DEBUG,
			"Inserting task(pid=%d) into hashlist", p->pid);
	std::pair<TaskHashListItr, bool> result = taskHashList_.insert(std::pair<pid_t, CTask*>(p->pid, &task));
	if (!result.second)
	{
		logEngine.WriteLog(enmLogLevel_ERROR, "Insert task(pid=%d) to hash list failed!", p->pid);
		return E_PS_INSERTHASHLISTFAIL;
	}
	return S_OK;
}

int32_t CProcessMgtBase::DelTaskFromProcessTree(CTask& task)
{
	struct task_struct* p = &task.task;
	//Make init inherit all the child processes
	while(NULL != p->p_cptr)
	{
		struct task_struct* tmp = p->p_cptr;

		p = p->p_osptr;
		tmp->p_ysptr = NULL;
		tmp->p_pptr = tmp->p_opptr;
		if (NULL != tmp->p_osptr)
		{
			tmp->p_osptr->p_ysptr = tmp;
		}
		tmp->p_pptr->p_cptr = tmp;
	}
	return S_OK;
}


CTask* CProcessMgtBase::GetTaskFromHashList(pid_t pid)
{
	TaskHashListItr itr = FindTaskFromHashList(pid);
	if (TASK_HASH_LIST_NULL == itr)
	{
		return NULL;
	}
	return itr->second;
}

bool CProcessMgtBase::IsTaskOnRunQueue(const CTask& task)
{
	return RUNQUEUE_NULL != FindTaskFromQueue(task, *pRunQueue_);
}

bool CProcessMgtBase::IsTaskOnWaitQueue(const CTask& task)
{
	return WAITQUEUE_NULL != FindTaskFromQueue(task, *pWaitQueue_);
}

bool CProcessMgtBase::IsTaskOnHashList(pid_t pid)
{
	return TASK_HASH_LIST_NULL != FindTaskFromHashList(pid);
}

int32_t CProcessMgtBase::MoveTaskToRunQueueTail(CTask& task)
{
	TaskQueueItr itr = FindTaskFromQueue(task, *pRunQueue_);
	if (RUNQUEUE_END == itr)
	{
		logEngine.WriteLog(enmLogLevel_ERROR, "task not found on runqueue when CProcessMgtBase::MoveTaskToRunQueueTail()!");
		return E_PS_TASKNOTFOUND;
	}
	pRunQueue_->erase(itr);
	pRunQueue_->push_back(&task);
	return S_OK;
}
int32_t CProcessMgtBase::MoveTaskToWaitQueueTail(CTask& task)
{
	TaskQueueItr itr = FindTaskFromQueue(task, *pWaitQueue_);
	if (RUNQUEUE_END == itr)
	{
		logEngine.WriteLog(enmLogLevel_ERROR, "task not found on waitqueue when CProcessMgtBase::MoveTaskToRunQueueTail()!");
		return E_PS_TASKNOTFOUND;
	}
	pWaitQueue_->erase(itr);
	pWaitQueue_->push_back(&task);
	return S_OK;
}

int32_t CProcessMgtBase::InsertTaskToQueue(CTask& task, TaskQueue& queue)
{
	queue.push_back(&task);
	return S_OK;
}

CProcessMgtBase::TaskQueueItr CProcessMgtBase::FindTaskFromQueue(const CTask& task,
		const TaskQueue& queue)
{
	TaskQueueItr itr = const_cast<TaskQueue&>(queue).begin();
	for (; queue.end() != itr; ++itr)
	{
		if (NULL == *itr)
		{
			logEngine.WriteLog(enmLogLevel_FATAL, "Found NULL pointer of CTask in queue!");
			return const_cast<TaskQueue&>(queue).end();
		}
		if (task == **itr)
		{
			return itr;
		}
	}
	return itr;
}

int32_t CProcessMgtBase::DelTaskFromQueue(CTask& task, TaskQueue& queue)
{
	if (queue.empty())
	{
		logEngine.WriteLog(enmLogLevel_DEBUG, "task(%d) not found when CProcessMgtBase::DelTaskFromQueue(), queue is empty", task.task.pid);
		return E_PS_TASKNOTFOUND;
	}
	TaskQueueItr itr = FindTaskFromQueue(task, queue);
	if (queue.end() == itr)
	{
		logEngine.WriteLog(enmLogLevel_DEBUG, "task(%d) not found when CProcessMgtBase::DelTaskFromQueue()", task.task.pid);
		return E_PS_TASKNOTFOUND;
	}
	queue.erase(itr);
	return S_OK;
}

CTask* CProcessMgtBase::NextTask(CTask& task, TaskQueue& queue)
{
	if (queue.empty())
	{
		return NULL;
	}
	TaskQueueItr itr = FindTaskFromQueue(task, queue);
	if (queue.end() == itr)
	{
		return NULL;
	}
	if(queue.end() == (++itr))
	{
		return NULL;
	}
	return *itr;
}
